/**
 * Juice
 * com.juice.orange.game.util
 * InputMessage.java
 */
package com.hh.game.service.gateway.codec.websocket;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.hh.game.service.gateway.exception.CodecIllegalException;
import com.hh.game.service.gateway.manager.MessageConstant;
import io.netty.buffer.ByteBuf;

import java.util.Arrays;

/**
 * ------------------------------------------------
 * | short | string | int | string | obj | short|
 * ------------------------------------------------
 * | 2000 | version| len | route | data | 1000|
 * ------------------------------------------------
 * <p>
 * obj:
 * ---------------
 * |type|len|data|
 * ---------------
 * |byte|int|byte|
 * ---------------
 * <p>
 * type:
 * 0 byte | 1 json
 */
public class InputMessage {
    private String version;
    private String route;
    private JSONObject data;
    private String stringData;
    private byte[] bytes;
    private boolean isByte;
    private boolean isString;

    public static boolean isFullMessage(ByteBuf buf) {
        int len = buf.getInt(2);
        len += buf.getInt(2 + 4 + len);

        int readable = buf.readableBytes();
        return len + 1 + 2 + 4 + 4 + 2 == readable;
    }

    public static InputMessage buildInputMessage(ByteBuf buf) {
        if (isFullMessage(buf)) {
            short head = buf.readShort(); /// head
            if (head == MessageConstant.HEAD) {

                int versionLen = buf.readInt(); // version
                byte[] bytes = new byte[versionLen];
                buf.readBytes(bytes, 0, versionLen);
                String version = new String(bytes);

                int len = buf.readInt();

                short tail = buf.getShort(2 + 4 + versionLen + 4 + len + 1);
                if (tail == MessageConstant.TAIL) {
                    InputMessage msg = new InputMessage();
                    msg.version = version; // version

                    len = buf.readInt();
                    bytes = new byte[len];
                    buf.readBytes(bytes, 0, len); // route
                    msg.route = new String(bytes);

                    ////  data
                    byte dataTpe = buf.readByte();
                    len = buf.readInt(); // data.len
                    if(len > -1){
                        bytes =  new byte[len];
                        buf.readBytes(bytes, 0, len);
                    }else {
                        bytes = null;
                    }

                    switch (MessageDataType.getType(dataTpe)) {
                        case BYTE:
                            msg.isByte = true;
                            msg.bytes = bytes;
                            break;
                        case JSON:
                            String str = bytes == null ? null : new String(bytes);
                            msg.data = JSON.parseObject(str);
                            break;
                        case STRING:
                            msg.isString = true;
                            msg.stringData = bytes == null ? null : new String(bytes);
                            break;
                        default:
                            throw new CodecIllegalException("data type [" + dataTpe + "] not exist");
                    }
                    buf.readShort();
                    return msg;
                } else {
                    throw new CodecIllegalException("buffer tail not [" + MessageConstant.TAIL + "] ,was => [" + tail + "]");
                }
            } else {
                throw new CodecIllegalException("buffer head not [" + MessageConstant.HEAD + "] ,was => [" + head + "]");
            }
        }
        return null;
    }

    private InputMessage() {
    }

    public String getVersion() {
        return version;
    }

    public String getRoute() {
        return route;
    }

    public JSONObject getData() {
        return data;
    }

    public byte[] getBytes() {
        return bytes;
    }

    public boolean isByte() {
        return isByte;
    }

    public String getStringData() {
        return stringData;
    }

    public boolean isString() {
        return isString;
    }

    @Override
    public String toString() {
        String str = "InputMessage{" +
                "version=" + version +
                ", route='" + route + '\'';
        if (data != null) {
            str += ", data='" + data + '\'';
        }
        if (bytes != null) {
            str += ", bytes='" + Arrays.toString(bytes) + '\'';
        }
        if (stringData != null) {
            str += ", stringData='" + stringData + '\'';
        }
        str += '}';
        return str;
    }
}
